package me.hekr.iotos.api.service;

import java.util.List;
import java.util.Map;
import java.util.Set;

import me.hekr.iotos.api.dto.*;
import me.hekr.iotos.api.dto.klink.AddTopoResp;
import me.hekr.iotos.api.dto.klink.BatchAddTopoResp;
import me.hekr.iotos.api.dto.klink.KlinkResp;
import me.hekr.iotos.api.dto.klink.ModelData;
import me.hekr.iotos.api.dto.klink.TopoSub;
import me.hekr.iotos.api.enums.DeviceType;
import me.hekr.iotos.api.util.Pagec;
import okhttp3.HttpUrl;
import okhttp3.MultipartBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.HTTP;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Part;
import retrofit2.http.Path;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;

/**
 * 注意路径不要加前缀 /，
 *
 * @see retrofit2.Retrofit.Builder#baseUrl(HttpUrl)
 */
public interface RetrofitIotService {
  Logger log = LoggerFactory.getLogger(RetrofitIotService.class);

  /**
   * 获取产品列表
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E8%8E%B7%E5%8F%96%E4%BA%A7%E5%93%81%E5%88%97%E8%A1%A8.html">获取产品列表</a>
   *
   * @param page 当前页，从0开始
   * @param size 分页大小，最大100，最小1
   * @return 分页产品
   */
  @GET("product")
  Call<Pagec<ProductDTO>> getProduct(@Query("page") int page, @Query("size") int size);

  /** 超级管理员可获取全局产品 */
  @GET("admin/productList")
  Call<Pagec<ProductDTO>> getAdminProduct(@Query("page") int page, @Query("size") int size);

  @GET("admin/dataShapeScript/{pk}")
  Call<DataShapeScriptDTO> getAdminDataShape(@Path("pk") String pk);

  @PUT("admin/dataShapeScript/{pk}")
  Call<DataShapeScriptDTO> adminCreateOrUpdateDataShape(
      @Path("pk") String pk, @Body DataShapeScriptDTO script);

  @GET("admin/deviceInfo/{pk}/{devId}")
  Call<DeviceApiDTO> getAdminDevice(@Path("pk") String pk, @Path("devId") String devId);

  @POST("admin/addDevice")
  Call<DeviceApiDTO> adminAddDevice(@Body DeviceAddReq reqDto);

  /** 超级管理员获取聚合 */
  @GET("admin/deviceStat/agglog/{pk}/{devId}")
  Call<DeviceAggPacketResp> adminGetDeviceStatAggLog(
      @Path("pk") String pk,
      @Path("devId") String devId,
      @Query(value = "startTime") Long startTime,
      @Query(value = "endTime") Long endTime,
      @Query(value = "key") String key,
      @Query(value = "span") String span);

  @GET("admin/deviceStat/kvlog/{pk}/{devId}")
  Call<List<DevicePacketMeasurement>> adminGetDeviceStatVersion(
      @Path("pk") String pk,
      @Path("devId") String devId,
      @Query(value = "startTime") long startTime,
      @Query(value = "endTime") long endTime,
      @Query(value = "key") String key);

  @Multipart
  @POST("admin/addUpgradeFile")
  Call<UploadResult> adminAddUpgradeFile(@Part MultipartBody.Part file);

  @POST("admin/addUpgrade")
  Call<Void> adminAddUpgrade(@Body DeviceUpgradeReq reqDto);

  @DELETE("admin/delete/{pk}/{id}")
  Call<Void> adminDeleteUpgrade(@Path("pk") String pk, @Path("id") String id);

  @POST("admin/disable/{pk}/{id}")
  Call<Void> adminDisableUpgrade(@Path("pk") String pk, @Path("id") String id);

  @POST("admin/enable/{pk}/{id}")
  Call<Void> adminEnableUpgrade(@Path("pk") String pk, @Path("id") String id);

  @GET("admin/upgradeList")
  Call<Pagec<UpgradeTaskDTO>> adminGetUpgradeList(
      @Query(value = "pk") List<String> pkList,
      @Query(value = "type") String type,
      @Query(value = "page") Integer page,
      @Query(value = "size") Integer size);

  /** 超级管理员按pk列表获取产品 */
  @GET("admin/productList/pks")
  Call<List<ProductDTO>> getAdminProductInfoListByPks(@Query("pks") Set<String> pks);

  /** 超管删除产品 */
  @DELETE("admin/product/{pk}")
  Call<Void> adminDeleteProduct(@Path("pk") String pk);

  /** 超级管理员按pk列表获取产品物模型 */
  @GET("admin/model/protocolByPks")
  Call<List<ModelProtocolDTO>> getAdminModelByPks(@Query("pks") Set<String> pks);

  /** 创建产品 */
  @POST("product")
  Call<ProductDTO> createProduct(@Body ConsoleProductReq consoleProductReq);

  /** 修改产品 */
  @PUT("product")
  Call<ProductDTO> editProduct(@Body ConsoleUpdateProductReq consoleUpdateProductReq);

  /**
   * 获取产品物模型
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E4%BA%A7%E5%93%81%E7%89%A9%E6%A8%A1%E5%9E%8B%E6%9F%A5%E8%AF%A2.html">产品物模型查询</a>
   *
   * @param pk 产品PK
   * @return 物模型
   */
  @GET("model/protocol/{pk}")
  Call<ModelProtocolDTO> getProtocol(@Path("pk") String pk);

  /** 超管获取上下行 */
  @GET("admin/getDevicePackage/{pk}/{devId}")
  Call<List<DevicePacketResp>> adminGetDevicePackage(
      @Path("pk") String pk,
      @Path("devId") String devId,
      @Query("startTime") Long startTime,
      @Query("endTime") Long endTime,
      @Query("action") String action,
      @Query("page") int page,
      @Query("size") int size);

  /** 超管获取设备快照 */
  @GET("admin/getSnapshot")
  Call<Snapshot> adminGetDeviceSnapshot(@Query("pk") String pk, @Query("devId") String devId);

  /** 超管获取拓扑设备 */
  @GET("admin/topo")
  Call<Pagec<DeviceDTO>> adminGetDeviceTopo(
      @Query("pk") String parentPk,
      @Query("devId") String parentDevId,
      @Query("page") int page,
      @Query("size") int size);

  /** 超管新增拓扑关系 */
  @PUT("admin/addTopo/{pk}/{devId}")
  Call<AddTopoResp> adminAddTopo(
      @Path("pk") String pk, @Path("devId") String devId, @Body DeviceDTO sub);

  @HTTP(method = "DELETE", path = "admin/delTopo/{pk}/{devId}", hasBody = true)
  Call<DelTopoResp> adminDelTopo(
      @Path("pk") String pk, @Path("devId") String devId, @Body DeviceDTO sub);

  @Multipart
  @PUT("admin/batchAddTopo/{pk}/{devId}")
  Call<BatchAddTopoResp> adminBatchAddTopo(
      @Path("pk") String pk,
      @Path("devId") String devId,
      @Query("overwrite") boolean overwrite,
      @Part MultipartBody.Part file);

  /** 超级管理员可获取全局物模型 */
  @GET("admin/model/protocol/{pk}")
  Call<ModelProtocolDTO> getAdminProtocol(@Path("pk") String pk);

  /** 超级管理员创建物模型 */
  @POST("admin/model/protocol/{pk}")
  Call<ModelProtocolDTO> adminCreateModel(
      @Path("pk") String pk, @Body ModelProtocolDTO modelProtocol);

  /** 超管新增物模型参数 */
  @POST("admin/model/protocol/{pk}/param")
  Call<ModelProtocolDTO> adminAddModelParam(
      @Path("pk") String pk, @Body ModelParamDTO modelParamDTO);
  /** 超管修改物模型参数 */
  @PUT("admin/model/protocol/{pk}/param")
  Call<ModelProtocolDTO> adminUpdateModelParam(
      @Path("pk") String pk, @Body ModelParamDTO modelParamDTO);

  /** 删除物模型参数 */
  @DELETE("admin/model/protocol/{pk}/param/{param}")
  Call<ModelProtocolDTO> adminDeleteModelParam(@Path("pk") String pk, @Path("param") String param);

  /** 超管新增物模型命令 */
  @POST("admin/model/protocol/{pk}/cmd")
  Call<ModelProtocolDTO> adminAddModelCmd(@Path("pk") String pk, @Body ModelCmdDTO modelCmdDTO);
  /** 超管修改物模型命令 */
  @PUT("admin/model/protocol/{pk}/cmd")
  Call<ModelProtocolDTO> adminUpdateModelCmd(@Path("pk") String pk, @Body ModelCmdDTO modelCmdDTO);

  /** 删除物模型命令 */
  @DELETE("admin/model/protocol/{pk}/cmd/{cmd}")
  Call<ModelProtocolDTO> adminDeleteModelCmd(@Path("pk") String pk, @Path("cmd") String cmd);

  /**
   * 新增设备
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%96%B0%E5%A2%9E%E8%AE%BE%E5%A4%87.html">新增设备</a>
   *
   * @param addReq 产品信息
   * @return 添加的设备信息
   */
  @POST("api/device/addDevice")
  Call<DeviceApiDTO> createDevice(@Body DeviceAddReq addReq);

  /**
   * 获取批次下所有设备
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E8%8E%B7%E5%8F%96%E6%89%B9%E6%AC%A1%E4%B8%8B%E6%89%80%E6%9C%89%E8%AE%BE%E5%A4%87.html">获取批次下所有设备</a>
   *
   * @param pk 产品PK
   * @param batchName 批次名称
   * @return 设备列表
   */
  @GET("api/device/getBatchDevices/{pk}/{batchName}")
  Call<List<DeviceApiDTO>> getBatchDevices(
      @Path("pk") String pk, @Path("batchName") String batchName);

  /**
   * 更改设备名称
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9B%B4%E6%96%B0%E8%AE%BE%E5%A4%87.html">更改设备名称</a>
   *
   * @param req 设备信息（pk，devId，name）
   * @return 空
   */
  @PUT("api/device/updateName")
  Call<Void> updateName(@Body DeviceUpdateNameReq req);

  /**
   * 查询设备详情
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E8%AE%BE%E5%A4%87%E8%AF%A6%E6%83%85.html">查询设备详情</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @return 返回设备信息
   */
  @GET("api/device/deviceInfo/{pk}/{devId}")
  Call<DeviceApiDTO> getDevice(@Path("pk") String pk, @Path("devId") String devId);

  /**
   * 批量查询状态
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%89%B9%E9%87%8F%E6%9F%A5%E8%AF%A2%E7%8A%B6%E6%80%81.html">批量查询状态</a>
   *
   * @param req 设备信息（pk，devId，name）
   * @return 设备信息列表
   */
  @POST("api/device/getDeviceStatus")
  Call<List<DeviceStatusRes>> getDeviceStatus(@Body DevIdListReq req);

  @POST("admin/cloudSend/{pk}/{devId}")
  Call<KlinkResp> adminDeviceCloudSend(
      @Path("pk") String pk, @Path("devId") String devId, @Body ModelData data);

  /**
   * 查询设备指标趋势
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E8%AE%BE%E5%A4%87%E6%8C%87%E6%A0%87%E8%B6%8B%E5%8A%BF.html">查询设备指标趋势</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @param req 设备信息（pk，devId，name）
   * @return 设备信息列表
   */
  @POST("api/deviceStat/kvlog/{pk}/{devId}")
  Call<List<ParamValue>> getParamValue(
      @Path("pk") String pk, @Path("devId") String devId, @Body ParamValueQuery req);

  /**
   * 获取鉴权信息
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E8%8E%B7%E5%8F%96Token.html">获取鉴权信息</a>
   *
   * @return 鉴权信息
   */
  @GET("api/user/getLoginToken")
  Call<LoginRsp> getLoginToken();

  /**
   * 新增设备
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%96%B0%E5%A2%9E%E8%AE%BE%E5%A4%87.html">新增设备</a>
   *
   * @param reqDto 设备信息（pk，devId，name）
   * @return 设备信息
   */
  @POST("api/device/addDevice")
  Call<DeviceApiDTO> addDevice(@Body DeviceAddReq reqDto);

  /**
   * 导入设备
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E5%AF%BC%E5%85%A5%E8%AE%BE%E5%A4%87.html">导入设备</a>
   *
   * @param devIdListReq （产品PK和设备ID列表）
   * @return 包含批次名称和添加数量
   */
  @POST("api/device/batchAddDevices")
  Call<Map<String, Object>> batchAddDevices(@Body DevIdListReq devIdListReq);

  /**
   * 查询设备列表
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E8%AE%BE%E5%A4%87%E5%88%97%E8%A1%A8.html">查询设备列表</a>
   *
   * @param pk 产品PK
   * @param keyword 搜索关键词
   * @param page 当前页面，最大100，最小1
   * @param deviceType 节点类型（普通设备：GENERAL；中继设备：SWITCH；网关设备：GATEWAY；终端子设备：TERMINAL）
   * @param online 是否在线，true为在线
   * @param size 分页大小，默认10，
   * @return 设备信息
   */
  @GET("api/device/getDeviceList")
  Call<Pagec<DeviceApiDTO>> getDeviceList(
      @Query("pk") String pk,
      @Query("keyword") String keyword,
      @Query("page") int page,
      @Query("deviceType") DeviceType deviceType,
      @Query("online") Boolean online,
      @Query("size") int size);

  @GET("admin/getDeviceList")
  Call<Pagec<DeviceApiDTO>> getAdminDeviceList(
      @Query("pk") String pk,
      @Query("keyword") String keyword,
      @Query("page") int page,
      @Query("online") Boolean online,
      @Query("size") int size);

  /**
   * 查询设备详情
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E8%AE%BE%E5%A4%87%E8%AF%A6%E6%83%85.html">查询设备详情</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @return 设备信息
   */
  @GET("api/device/deviceInfo/{pk}/{devId}")
  Call<DeviceApiDTO> deviceInfo(@Path("pk") String pk, @Path("devId") String devId);

  /**
   * 查询设备影子
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E8%AE%BE%E5%A4%87%E5%BD%B1%E5%AD%90.html">查询设备影子</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @return 设备影子
   */
  @GET("api/device/getSnapshot")
  Call<Snapshot> getDeviceSnapshot(@Query("pk") String pk, @Query("devId") String devId);

  /**
   * 删除设备
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E5%88%A0%E9%99%A4%E8%AE%BE%E5%A4%87.html">删除设备</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @param delSnapshot 是否删除设备影子
   * @return 空
   */
  @DELETE("api/device/delDevice/{pk}/{devId}")
  Call<Void> delDevice(
      @Path("pk") String pk,
      @Path("devId") String devId,
      @Query("delSnapshot") boolean delSnapshot);

  /**
   * 查询历史上下行数
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E5%8E%86%E5%8F%B2%E4%B8%8A%E4%B8%8B%E8%A1%8C%E6%95%B0%E6%8D%AE.html">查询历史上下行数</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @param startTime 开始事件
   * @param endTime 结束事件
   * @param action 事件
   * @param page 当前页 从0开始
   * @param size 分页大小，最大100，最小1
   * @return 上下行数据信息
   */
  @GET("api/device/getDeviceHistoryData/{pk}/{devId}")
  Call<List<DevicePacketResp>> getDeviceHistoryData(
      @Path("pk") String pk,
      @Path("devId") String devId,
      @Query("startTime") Long startTime,
      @Query("endTime") Long endTime,
      @Query("action") String action,
      @Query("cmd") String cmd,
      @Query("page") int page,
      @Query("size") int size);

  /**
   * 下发控制命令
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E4%B8%8B%E5%8F%91%E6%8E%A7%E5%88%B6%E5%91%BD%E4%BB%A4.html">下发控制命令</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @param data （cmd 命令标识符 ，params 参数值）
   * @return 指令信息
   */
  @POST("api/device/cloudSend/{pk}/{devId}")
  Call<KlinkResp> deviceCloudSend(
      @Path("pk") String pk, @Path("devId") String devId, @Body ModelData data);

  /**
   * 查询命令状态
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E5%91%BD%E4%BB%A4%E7%8A%B6%E6%80%81.html">查询命令状态</a>
   *
   * @param messageId 所查询命令的ID
   * @return 命令信息
   */
  @GET("api/device/cloudSendMsgInfo/{messageId}")
  Call<CloudSendMsgDTO> cloudSendMsgInfo(@Path("messageId") String messageId);

  /**
   * 查询历史控制命令
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E5%8E%86%E5%8F%B2%E6%8E%A7%E5%88%B6%E5%91%BD%E4%BB%A4.html">查询历史控制命令</a>
   *
   * @param page 当前页面，最小0
   * @param size 分页大小，最大100，最小0
   * @param pk 产品PK
   * @param devId 设备ID
   * @param startTime 查询开始时间
   * @param endTime 查询结束事件
   * @return 命令信息
   */
  @GET("api/device/cloudSendMsgList")
  Call<Pagec<CloudSendMsgDTO>> cloudSendMsgList(
      @Query("page") Integer page,
      @Query("size") Integer size,
      @Query("pk") String pk,
      @Query("devId") String devId,
      @Query("startTime") Long startTime,
      @Query("endTime") Long endTime);

  /**
   * 网关添加子设备
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E7%BD%91%E5%85%B3%E6%B7%BB%E5%8A%A0%E5%AD%90%E8%AE%BE%E5%A4%87.html">网关添加子设备</a>
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @param sub 子设备
   * @return 添加的子设备信息
   */
  @PUT("api/device/addTopo/{pk}/{devId}")
  Call<AddTopoResp> addTopo(@Path("pk") String pk, @Path("devId") String devId, @Body TopoSub sub);

  /**
   * 网关删除子设备
   *
   * @param pk 产品PK
   * @param devId 设备ID
   * @param sub 子设备
   * @return 删除的子设备信息
   */
  @PUT("api/device/delTopo/{pk}/{devId}")
  Call<DelTopoResp> delTopo(@Path("pk") String pk, @Path("devId") String devId, @Body TopoSub sub);

  /**
   * 查询设备指标聚合
   *
   * <p><a
   * href="http://hy.hekr.me/iot-docs-test/web/content/%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/%E6%9F%A5%E8%AF%A2%E8%AE%BE%E5%A4%87%E6%8C%87%E6%A0%87%E8%81%9A%E5%90%88.html">查询设备指标聚合</a>
   *
   * @param pk pk
   * @param devId devId
   * @param params 参数
   * @return DeviceAggPacketResp
   */
  @GET("api/deviceStat/agglog/{pk}/{devId}")
  Call<DeviceAggPacketResp> getDeviceAggData(
      @Path("pk") String pk, @Path("devId") String devId, @QueryMap Map<String, Object> params);

  /** 获取萧山资源目录系统资源列表接口 */
  @GET("cat/system")
  Call<Object> getSystem();

  /** 获取萧山资源目录下拉信息接口 */
  @GET("cat/product")
  Call<Object> getCatProduct();
}
